
#include "libamr/amr2wavcode.h"
#include "gkt_voice_lib.h"
#include "gkt_debug.h"

#if GKT_CONFIG_VOICE_OUTPUT_ENABLE

#if 0
#define voice_output_decode_volume_adjust(output, sp_data, sp_nums)	\
	do {	\
		gkt_unused(output);	\
		gkt_unused(sp_data);	\
		gkt_unused(sp_nums);	\
	} while (0)
#else
/* software voice volume/amplitude attr */
typedef struct _voice_output_volume_attr {
	int16_t	multiplier;
	int16_t	divisor;
} voice_output_volume_attr_s;

#ifdef GKT_CONFIG_VOICE_OUTPUT_VOLUME_ATTRS
static const voice_output_volume_attr_s sc_voice_output_volume_attrs[] =
	{ GKT_CONFIG_VOICE_OUTPUT_VOLUME_ATTRS };
#else
static const voice_output_volume_attr_s sc_voice_output_volume_attrs[] =
	{ { 12, 10 }, { 8, 10 }, { 5, 10 }};
#endif
#define VOICE_OUTPUT_VOLUME_INT16_MAX (32767)
#define VOICE_OUTPUT_VOLUME_INT16_MIN (-32768)
static void voice_output_decode_volume_adjust(uint32_t volume,
				int16_t *sp_value)
{
	const voice_output_volume_attr_s *c_amp_attr;
	int32_t value, value_orig;

	if (volume >= 3)//GKT_VOICE_OUTPUT_VOLUME_MAX
		return;

	c_amp_attr = &sc_voice_output_volume_attrs[volume];
	if ((c_amp_attr->multiplier > 0)
		&& (c_amp_attr->divisor > 0))
	{
		value_orig = (int32_t)(*sp_value);
		value = (value_orig * c_amp_attr->multiplier) / c_amp_attr->divisor;
		if (value <= VOICE_OUTPUT_VOLUME_INT16_MIN)
			*sp_value = VOICE_OUTPUT_VOLUME_INT16_MIN;
		else if (value >= VOICE_OUTPUT_VOLUME_INT16_MAX)
			*sp_value = VOICE_OUTPUT_VOLUME_INT16_MAX;
		else
			*sp_value = (int16_t)value;
	}
}
#endif

#if defined(GKT_VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE)
#define VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE GKT_VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE
#else
#define VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE 1
#endif
static uint32_t s_volume = 0;
static void voice_decode_sp_multiple(int16_t *dec_sp, 
				int16_t sp_value_cur, int16_t sp_value_next)
{
	int16_t sp_value_step;

	voice_output_decode_volume_adjust(s_volume, &sp_value_cur);
	voice_output_decode_volume_adjust(s_volume, &sp_value_next);

	dec_sp[0] = sp_value_cur;
#if (VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE == 2)
	sp_value_step = (sp_value_next - sp_value_cur) / 2;
	dec_sp[1] = (int16_t)(sp_value_cur + sp_value_step);
#elif (VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE == 4)
	sp_value_step = (sp_value_next - sp_value_cur) / 16;
	dec_sp[1] = (int16_t)(sp_value_cur + sp_value_step * 3);
	dec_sp[2] = (int16_t)(sp_value_cur + sp_value_step * 8);
	dec_sp[3] = (int16_t)(sp_value_cur + sp_value_step * 13);
#elif (VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE == 6)
	sp_value_step = (sp_value_next - sp_value_cur) / 18;
	dec_sp[1] = (int16_t)(sp_value_cur + sp_value_step * 2);
	dec_sp[2] = (int16_t)(sp_value_cur + sp_value_step * 5);
	dec_sp[3] = (int16_t)(sp_value_cur + sp_value_step * 9);
	dec_sp[4] = (int16_t)(sp_value_cur + sp_value_step * 13);
	dec_sp[5] = (int16_t)(sp_value_cur + sp_value_step * 16);
#else
	gkt_unused(sp_value_next);
	gkt_unused(sp_value_step);
#endif
}

static int16_t *s_dec_buff_output_sp_prev = NULL;
static int16_t s_dec_sp_value_prev = 0;
static void voice_decode_dec_buff_adjust(const int16_t *dec_buff, 
				void *dec_buff_output, uint32_t sp_nums, int frame_type)
{
	int16_t *dec_sp = (int16_t*)dec_buff_output;
	int16_t sp_value_cur, sp_value_next;
	uint32_t i;

	sp_value_cur = dec_buff[0];
	for (i = 0; i < sp_nums; i++) {
		if ((i + 1) < sp_nums) {	/* the first or middle sp of the frame */
			if (!i && s_dec_buff_output_sp_prev) {
				/* the first sp of the current frame,
				 * if needed, process the last sp of the previous frame */
				voice_decode_sp_multiple(s_dec_buff_output_sp_prev, 
					s_dec_sp_value_prev, sp_value_cur);
				s_dec_buff_output_sp_prev = NULL;	/* !!! clear timely */
			}

			sp_value_next = dec_buff[i + 1];
		}
		else {	/* the last sp of the frame */
			/* 
			 * 1. calculate with itself as default
			 * 2. if not the last frame, save s_dec_buff_output_sp_prev and s_dec_sp_value_prev
			 *    as pending
			 */
			sp_value_next = sp_value_cur;
			if (frame_type != GKT_FRAME_TYPE_TAIL) {
				s_dec_buff_output_sp_prev = dec_sp;
				s_dec_sp_value_prev = sp_value_cur;
			}
		}

		voice_decode_sp_multiple(dec_sp, sp_value_cur, sp_value_next);
		sp_value_cur = sp_value_next;
		dec_sp += VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE;
	}
}

#endif

static int32_t *s_destate = NULL;
uint32_t gkt_voice_decode(uint32_t volume, uint32_t frame_nums,
			const void *enc_buff, void *dec_buff, gkt_frame_type isend)
{
	const uint8_t *enc_frame;
	uint8_t *dec_frame;
	uint32_t frame_idx;
	uint8_t dec_frame_temp[GKT_VOICE_DEC_OUTPUT_FRAME_SIZE*2];

	gkt_trace("voice_decode: frames(%u), frame_size(amr(%u) - wav(%u)), isend=%d\n", 
							frame_nums, frame_nums*GKT_VOICE_DEC_INPUT_FRAME_SIZE, frame_nums*GKT_VOICE_DEC_OUTPUT_FRAME_SIZE*2, isend);

	GKT_ASSERT(frame_nums);
	GKT_ASSERT(enc_buff);
	GKT_ASSERT(dec_buff);

	s_volume = volume;
	frame_idx = 0;
	enc_frame = (const uint8_t *)enc_buff;
	dec_frame = (uint8_t *)dec_buff;

#if GKT_VOICE_DEC_INPUT_FRAME_SIZE
	while (frame_idx < frame_nums) {
		if (GKT_FRAME_TYPE_HEAD == isend) {
			s_destate = DecodeAMRFileToWAVEFilePacket(s_destate, (uint8_t*)enc_frame, dec_frame_temp, 0);
			if (NULL == s_destate) {
				gkt_error("voice_decode: decode failed\n");
				return 0;
			}
			isend = GKT_FRAME_TYPE_MIDDLE;
		}
		else if (GKT_FRAME_TYPE_TAIL == isend) {
			if (NULL == s_destate) {
				gkt_error("voice_decode: decode failed\n");
				return 0;
			}
			if ((frame_nums - frame_idx) == 1) {
				s_destate = DecodeAMRFileToWAVEFilePacket(s_destate, (uint8_t*)enc_frame, dec_frame_temp, 2);
			}
			else
				s_destate = DecodeAMRFileToWAVEFilePacket(s_destate, (uint8_t*)enc_frame, dec_frame_temp, 1);
		}
		else {
			if (NULL == s_destate) {
				gkt_error("voice_decode: decode failed, s_destate is null\n");
				return 0;
			}
			s_destate = DecodeAMRFileToWAVEFilePacket(s_destate, (uint8_t*)enc_frame, dec_frame_temp, 1);
		}
		voice_decode_dec_buff_adjust((int16_t*)dec_frame_temp, dec_frame, GKT_VOICE_DEC_OUTPUT_FRAME_SIZE, isend);
		enc_frame += GKT_VOICE_DEC_INPUT_FRAME_SIZE;
		dec_frame += ((GKT_VOICE_DEC_OUTPUT_FRAME_SIZE*2)*GKT_VOICE_DEC_CONVERSION_SAMPLE_MULTIPLE);
		frame_idx++;
	}
	return (frame_nums*GKT_VOICE_DEC_INPUT_FRAME_SIZE);
#else
	return 0;
#endif
}

void gkt_voice_decode_stop(void)
{
	if (s_destate) {
		gkt_trace("gkt_voice_decode_stop! \n");
		Decoder_Interface_exit(s_destate);
		s_destate = NULL;	// agan - 2024-09-05
	}
}

int gkt_voice_lib_init(void)
{
	return GKT_SUCCESS;
}

